package org.west.sky.scripture.elegantdemo.utils;

import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.west.sky.scripture.elegantdemo.annotation.Dict;
import org.west.sky.scripture.elegantdemo.exception.BizException;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: chz
 * @date: 2023/3/6
 * @description: 数据字典工具类
 */
@Component
public class DictUtil {
    /**
     * 使用个缓存，避免列表数据多次进行字典查询
     */
    private static final ThreadLocal<Map<String, Map<String, String>>> cache = ThreadLocal.withInitial(ConcurrentHashMap::new);

    public static Object parseResult(Object result) throws Exception {
        //判断空
        if (Objects.isNull(result)) {
            return null;
        }
        //判断结果类型
        if (result instanceof List) {
            //LIST类型
            for (Object obj : (List<?>) result) {
                parseDict(obj);
            }
        }
        //todo 处理分页的数据
//        else if (result instanceof PageInfo<?>) {
//            //自定义的分页返回结果集类型  实际结果在 list字段中。 处理和LIST一致
//            PageInfo<?> pageResult = (PageInfo<?>) result;
//            for (Object obj : pageResult.getList()) {
//                parseDict(obj);
//            }
//            //分页数据中 重新放入结果
//            return pageResult;
//        }
        else {
            //单实例对象类型
            parseDict(result);
        }
        return result;
    }

    /**
     * 字典转换
     *
     * @param obj
     */
    private static void parseDict(Object obj) throws NoSuchFieldException, IllegalAccessException, BizException {
        Field[] fields = obj.getClass().getDeclaredFields();
        //非空判断
        if (fields.length == 0) {
            return;
        }
        for (Field field : fields) {
            //判断每一个字典是否有Dict注解
            if (Objects.nonNull(field.getAnnotation(Dict.class))) {
                handleDict(obj, field);
            }
        }
    }

    /**
     * 处理字典注解的字段
     *
     * @param obj
     * @param field
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private static void handleDict(Object obj, Field field) throws NoSuchFieldException, IllegalAccessException, BizException {
        Dict dict = field.getAnnotation(Dict.class);
        boolean local = dict.isLocal();
        if (local) {
            handleLocalDict(obj, field, dict);
        } else {
            handleOnlineDict(obj, field, dict);
        }
    }

    /**
     * 处理本地字典转换的逻辑
     *
     * @param obj
     * @param field
     * @param dict
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private static void handleLocalDict(Object obj, Field field, Dict dict) throws NoSuchFieldException, IllegalAccessException {
        String suffix = dict.suffix();
        String dictVal = dict.dictVal();
        field.setAccessible(true);
        Object key = field.get(obj);
        if (StringUtils.isEmpty(dictVal) || Objects.isNull(key)) {
            return;
        }
        Map<String, String> dictValMap = getLocalDictValMap(dictVal);
        Field name = obj.getClass().getDeclaredField(field.getName() + suffix);
        name.setAccessible(true);
        name.set(obj, dictValMap.get(key.toString()));
        name.setAccessible(false);
        field.setAccessible(false);
    }

    /**
     * 处理在线字典转换的逻辑
     *
     * @param obj
     * @param field
     * @param dict
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private static void handleOnlineDict(Object obj, Field field, Dict dict) throws NoSuchFieldException, IllegalAccessException, BizException {
        String suffix = dict.suffix();
        String dictCode = dict.dictCode();
        field.setAccessible(true);
        Object key = field.get(obj);
        if (StringUtils.isEmpty(dictCode) || Objects.isNull(key)) {
            return;
        }
        Map<String, String> dictValMap = getOnlineDictValMap(dictCode);
        Field name = obj.getClass().getDeclaredField(field.getName() + suffix);
        name.setAccessible(true);
        name.set(obj, dictValMap.get(key.toString()));
        name.setAccessible(false);
        field.setAccessible(false);
    }

    /**
     * 获取本地字典值列表，格式要求：1:草稿,2:已提交,3:已删除
     *
     * @param dictVal 字典键值对
     * @return 字典列表
     */
    private static Map<String, String> getLocalDictValMap(String dictVal) {
        if (StringUtils.isEmpty(dictVal)) {
            return Collections.emptyMap();
        }
        Map<String, Map<String, String>> dictMap = cache.get();
        if (dictMap.containsKey(dictVal)) {
            return dictMap.get(dictVal);
        }
        Map<String, String> valMap = new HashMap<>();
        String[] split = dictVal.split("；");
        for (String s : split) {
            String[] val = s.split("：");
            if (val.length != 2) {
                continue;
            }
            valMap.put(val[0], val[1]);
        }
        dictMap.put(dictVal, valMap);
        cache.set(dictMap);
        return valMap;
    }

    /**
     * 获取字典服务那边的字典列表
     *
     * @param dictCode 字典编码
     * @return 字典列表
     */
    private static Map<String, String> getOnlineDictValMap(String dictCode) throws BizException {
        if (StringUtils.isEmpty(dictCode)) {
            return Collections.emptyMap();
        }
        Map<String, Map<String, String>> dictMap = cache.get();
        if (dictMap.containsKey(dictCode)) {
            return dictMap.get(dictCode);
        }
        //todo 根据业务改写
//        DictDataFeignClient dataFeignClient = SpringBootBeanUtil.getBean(DictDataFeignClient.class);
//        Map<String, String> dictItemMap = dataFeignClient.selectDictData(dictCode).stream().collect(Collectors.toMap(DictDataDto::getDictLabel, DictDataDto::getDictValue));
        Map<String, String> dictItemMap = mockOnlineDict(dictCode);
        if (CollectionUtils.isEmpty(dictItemMap)) {
            throw new BizException("字典转换失败!");
        }
        dictMap.put(dictCode, dictItemMap);
        cache.set(dictMap);
        return dictItemMap;
    }

    /**
     * 模拟从数据库或从其他服务获取字典信息
     *
     * @return
     */
    private static Map<String, String> mockOnlineDict(String dictCode) {
        Map<String, Map<String, String>> map = new HashMap<>();
        Map<String, String> sex = new HashMap<>();
        sex.put("1", "男生");
        sex.put("2", "女生");
        sex.put("0", "未知");
        map.put("sex", sex);
        return map.get(dictCode);
    }

    /**
     * 清除缓存
     */
    public static void clearCache() {
        cache.remove();
    }

}
